/*
 * @Author: 脉迈
 * @Date: 2021-08-06 17:33:29
 * @LastEditors: 脉迈
 * @LastEditTime: 2021-12-09 17:11:37
 */
import React, { useState, ReactNode } from "react";
import styles from "./Index.module.scss";
import { px2Rem } from "utils/helper";
interface propsType {
  style: any;
  defaultStyle: {
    height: number;
    width: number;
    left: number;
    top: number;
  };
  children?: ReactNode;
  active: boolean;
  handleMousedownProp: Function;
  handleElementMouseUpProp: Function;
  handleElementMoveProp: Function;
  handlePointMoveProp: Function;
  handlePointMouseUpProp: Function;
  handleContextMenuProp: Function;
  handleKeyPressProp: Function;
}
interface Res {
  [key: string]: string;
}
const ZoomComponent = ({
  style,
  active,
  defaultStyle,
  children,
  handleMousedownProp,
  handleElementMouseUpProp,
  handleElementMoveProp,
  handlePointMoveProp,
  handlePointMouseUpProp,
  handleContextMenuProp,
  handleKeyPressProp,
}: propsType) => {
  const [pointList] = useState(["lt", "rt", "lb", "rb", "l", "r", "t", "b"]);
  const [directionKey] = useState<Res>({ t: "n", b: "s", l: "w", r: "e" });

  /**
   * @description 主要目的是：阻止冒泡, 避免触发，嵌套的plugin组件里面的点击事件
   * @params  @type event
   */
  const handleTopWrapperClick = (
    e: React.MouseEvent<HTMLDivElement, MouseEvent>
  ) => {
    e.stopPropagation();
    e.preventDefault();
  };
  /**
   * !#zh 给 当前选中元素 添加鼠标移动相关事件
   *
   * @param {mouseEvent} e
   */
  const mousedownForElement = (
    e: React.MouseEvent<HTMLDivElement, MouseEvent>
  ) => {
    const pos = { ...defaultStyle }; // 获取当前传入的style
    let startY = e.clientY;
    let startX = e.clientX;
    let startTop = pos.top;
    let startLeft = pos.left;

    let move = (e: any) => {
      // 移动的时候，不需要向后代元素传递事件，只需要单纯的移动就OK
      e.stopPropagation();
      e.preventDefault();

      let currX = e.clientX;
      let currY = e.clientY;
      pos.top = currY - startY + startTop;
      pos.left = currX - startX + startLeft;
      handleElementMoveProp(pos);
    };

    let up = (e: any) => {
      handleElementMouseUpProp();
      document.removeEventListener("mousemove", move, true);
      document.removeEventListener("mouseup", up, true);
    };
    document.addEventListener("mousemove", move, true);
    document.addEventListener("mouseup", up, true);
    // TODO add comment
    return true;
  };
  /**
   * @description 鼠标按下选中当前组件
   * @param e event
   */
  const handleMouseDownOnElement = (
    e: React.MouseEvent<HTMLDivElement, MouseEvent>
  ) => {
    // 鼠标按下回传父组件的事件
    handleMousedownProp();
    // 添加鼠标移动事件
    mousedownForElement(e);
  };
  /**
   * @description 放大缩小
   * @param point 放大缩小点的位置
   * @param downEvent event
   */
  const handleMouseDownOnPoint = (
    point: any,
    downEvent: React.MouseEvent<HTMLDivElement, MouseEvent>
  ) => {
    downEvent.stopPropagation();
    downEvent.preventDefault(); // Let's stop this event.
    const pos = { ...defaultStyle }; // 获取当前传入的style
    let height = pos.height;
    let width = pos.width;
    let top = pos.top;
    let left = pos.left;
    let startX = downEvent.clientX;
    let startY = downEvent.clientY;
    let move = (moveEvent: any) => {
      let currX = moveEvent.clientX;
      let currY = moveEvent.clientY;
      let disY = currY - startY;
      let disX = currX - startX;
      let hasT = /t/.test(point);
      let hasB = /b/.test(point);
      let hasL = /l/.test(point);
      let hasR = /r/.test(point);
      let newHeight = +height + (hasT ? -disY : hasB ? disY : 0);
      let newWidth = +width + (hasL ? -disX : hasR ? disX : 0);
      pos.height = newHeight > 0 ? newHeight : 0;
      pos.width = newWidth > 0 ? newWidth : 0;
      pos.left = +left + (hasL ? disX : 0);
      pos.top = +top + (hasT ? disY : 0);
      handlePointMoveProp(pos);
    };
    let up = () => {
      handlePointMouseUpProp();
      document.removeEventListener("mousemove", move);
      document.removeEventListener("mouseup", up);
    };
    document.addEventListener("mousemove", move);
    document.addEventListener("mouseup", up);
  };
  /**
   * @description 获取point计算后样式
   * @param point
   * @returns {{}}
   */
  const getPointStyle = (point: string) => {
    const height = defaultStyle.height;
    const width = defaultStyle.width;
    let hasT = /t/.test(point);
    let hasB = /b/.test(point);
    let hasL = /l/.test(point);
    let hasR = /r/.test(point);
    let newLeft = 0;
    let newTop = 0;
    if (point.length === 2) {
      newLeft = hasL ? 0 : width;
      newTop = hasT ? 0 : height;
    } else {
      // !#zh 上下点，宽度固定在中间
      if (hasT || hasB) {
        newLeft = width / 2;
        newTop = hasT ? 0 : height;
      }
      // !#zh 左右点，高度固定在中间
      if (hasL || hasR) {
        newLeft = hasL ? 0 : width;
        newTop = height / 2;
      }
    }
    const style = {
      marginLeft: hasL || hasR ? "-3px" : 0,
      marginTop: hasT || hasB ? "-3px" : 0,
      // left: `${newLeft}px`,
      // top: `${newTop}px`,
      left: px2Rem(newLeft),
      top: px2Rem(newTop),
      cursor:
        point
          .split("")
          .reverse()
          .map((m) => directionKey[m])
          .join("") + "-resize",
    };
    return style;
  };

  return (
    <>
      <div
        className={`${styles.componentsEeditShape} ${
          active ? styles.active : ""
        }`}
        onKeyDown={(e) => {
          handleKeyPressProp(e);
        }}
        onMouseDown={(e) => {
          handleMouseDownOnElement(e);
        }}
        onClick={(e) => {
          handleTopWrapperClick(e);
        }}
        onContextMenu={(e) => {
          e.stopPropagation();
          e.preventDefault();
          let currX = e.clientX;
          let currY = e.clientY;
          const pos = { ...defaultStyle }; // 获取当前传入的style
          handleContextMenuProp({
            left: currX - pos.width - 100,
            top: currY - pos.height,
          });
        }}
        style={style}
      >
        {active &&
          pointList.map((item, index) => {
            return (
              <div
                className={styles["edit-shape-point"]}
                onMouseDown={(e) => {
                  handleMouseDownOnPoint(item, e);
                }}
                key={index}
                style={getPointStyle(item)}
              ></div>
            );
          })}
        {children}
      </div>
    </>
  );
};
export default ZoomComponent;
